#####################################################################
# File:         Report.py
# Product:      KnowledgeEngine
#
# Copyright:    Copyright (c) 2002, Faulkner Technologies.
# Author:       Brian Oliver
#
# Description:  This file defines the Report class, the abstract
#               base class for all Model Reports.
#
# See Also:     Model
#####################################################################

#####################################################################
## Knowledge Engine Library Imports
from Common import *
from GenericContainer import GenericContainer, GenericContainerInfo
from PropertyDefinition import PropertyDefinition
from PropertyTypes import *
from PropertyFormats import *
from PropertyStructures import *
from KERFProcessor import *
from Products.KnowledgeEngine.Environment.Environment import Environment

#####################################################################
## Zope Library Imports
from Globals import InitializeClass
from Globals import DTMLFile
from Globals import Persistent
from ImageFile import ImageFile

#####################################################################
## Python Library Imports
# (none)

#####################################################################
## ReportInfo Class Definition
class ReportInfo(GenericContainerInfo):
    """
        Defines the class info methods, defining information about
        the class without needing an instance of the class
    """
    
    #---------------------------------------------------------------#
    
    def getClassName(self):
        """
            Returns the name of the class for which 
            we are providing information.
        """
        return 'Report'

    #---------------------------------------------------------------#

    def getDisplayName(self):
        """
            Return a friendly name for the class instances
            (this is used for displaying in lists etc)
        """
    
        return "Report"
        
    #---------------------------------------------------------------#

    def getIdentityType(self):
        """
            ABSTRACT: Return the identity type.  
            
            This is a short string used for prefixing object identities
        """
        
        return "report"

    #---------------------------------------------------------------#

    def isInstanceOf(self, className):
        """
            Returns if the class is an instance of the specified
            className, or implements the interface specified 
            by the className
        """

        return className == 'Report' or GenericContainerInfo.isInstanceOf(self, className) 
        
    #---------------------------------------------------------------#

    def isPermittedInContainer(self, containerClassInfo, containerInstance = None, instance=None):
        """
            ABSTRACT: Returns if class instances (instance) is permitted in 
            the specified container (containerInstance)
            
            NOTE: This is from this class' instance perspective.
        """
        
        #DEFAULT RULE: Reports are only permitted in Models
        return containerClassInfo.isInstanceOf('Model')

    #---------------------------------------------------------------#

    def isChildPermitted(self, childClassInfo, childInstance = None):
        """
            Returns if the specified child is permitted as a 
            child of the class' instances.
            
            NOTE: This is from this class' instance perspective.
            
            For component containers, this always overrides what the
            return value from childClassInfo.isPermittedInContainer(...)
        """
        
        #DEFAULT RULE: Reports don't contain anything but events (specialised reports may)
        return childClassInfo.isInstanceOf('Event')
    
    #---------------------------------------------------------------#

    def onConfigureProperties(self):
        """
            Automatically called by the Knowledge Engine once
            the class has been loaded.  Use this method to register 
            class specific properties using the PropertyReflection interface.
            
            If this class is sub-classed, a call must be made to
            the super-class to ensure super-class properties are
            correctly registered
            
            NOTE: This method is called before ClassInfo.onAfterStartup()            
        """

        #initialise the super-class properties for reflection
        GenericContainerInfo.onConfigureProperties(self)

        #add the 'order' property (set to something large so reports appear at the end of the ordered containers)      
        self.addPropertyDefinition(PropertyDefinition(identity="order", displayName="Order", description="The relative position of the component with in it's container", defaultValue=100000, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC, isWritePermitted=true, isForConstructor=false, isForPropertyEditor=false))        

    #---------------------------------------------------------------#

#####################################################################
## Report Class Definition
class Report(GenericContainer):
    """
        Base container for all Faulkner KnowledgeEngine Reports
    """

    #---------------------------------------------------------------#

    #ABSTRACT TRANSIENT: a ClassInfo implementation instance to provide info about this class
    _CLASSINFO = ReportInfo()
 
    #---------------------------------------------------------------#

    def __init__(self, id, identity):
        "Constructor for the object"        
        
        GenericContainer.__init__(self, id, identity)

    #---------------------------------------------------------------#

    def getEnvironment(self):
        "Return the KnowledgeEngine Environment in which this Model is located"
        
        lParent = self.getParent()
        
        while not isinstance(lParent, Environment):
            lParent = lParent.getParent()
        
        return lParent

    #---------------------------------------------------------------#

    def getReportType(self):
        """
            Returns the type of report. Options may include
            'single' - a report designed for a single user
            'grouped' - reports designed for grouping assessments
            
            by default we return 'single'
        """

        return 'single'
    
    #---------------------------------------------------------------#

    def getModel(self):
        """
            Return the Model which contains this Report
        """

        return self.getParent()
    
    #---------------------------------------------------------------#

    def getAssessmentsByValue(self, cid, value):
        """
            Return the Assessment ID from a components value
            
            Returns the full recordset
        """

        assessments = []
        
        #First try the texts table
        sql = "SELECT assessmentid FROM texts WHERE cid='%s' and value='%s'" % (cid, value)
        (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)

        if len(resultset) == 0:
            #Try the booleans table
            sql = "SELECT assessmentid FROM booleans WHERE cid='%s' and value='%s'" % (cid, value)
            (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)
            if len(resultset) == 0:
                #Couldnt find any so return
                return assessments
        
        for row in resultset:
            assessments = assessments + [row[0]]
        
        return assessments
        
    #---------------------------------------------------------------#

    def getValuesByComponent(self, cid):
        """
            Return the distinct values for a component ID
            
        """

        values = []
        
        #First try the texts table
        sql = "SELECT distinct value FROM texts WHERE cid='%s'" % (cid)
        (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)

        if len(resultset) == 0:
            #Try the booleans table
            sql = "SELECT distinct value FROM booleans WHERE cid='%s'" % (cid)
            (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)
            if len(resultset) == 0:
                #Couldnt find any so return
                return values
        
        for row in resultset:
            values = values + [row[0]]
        
        return values
        
    #---------------------------------------------------------------#

    def getState(self, aid, cid):
        """
            Return the state of any component.
            
            Returns text of a text value or true/false if boolean
        """

        #First try the texts table
        sql = "SELECT value FROM texts WHERE cid='%s' and assessmentid='%s'" % (cid, aid)
        (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)

        if len(resultset) > 0:
            return resultset[0][0]
        else:
            #Now try the booleans table
            sql = "SELECT value FROM booleans WHERE cid='%s' and assessmentid='%s'" % (cid, aid)
            (columns, resultset) = self.getModel().getDatabaseConnection().query(sql)
            if len(resultset) > 0:
                return resultset[0][0]
            else:
                return false
            
      #---------------------------------------------------------------#

    def resolveKERFProperties(self, kerf, assessmentCache, component=None, componentContext=None):
        """
            Resolves the <$ ... $> component property references
            in the specified kerf using the provided assessment cache

            RETURNS: a python expression that may be evaluated with eval
        """

        return resolveKERFProperties(kerf, assessmentCache, component, componentContext)
    
    #---------------------------------------------------------------#

    def resolveKERF(self, content, assessmentCache, component=None, componentContext=None):
        """
            Resolves the <kerf>...</kerf> (Knowledge Engine Report Fields)
            markups in the specified content (a string) given an
            assessment cache.
        """

        return resolveKERF(content, assessmentCache, component, componentContext)
    
    #---------------------------------------------------------------#

#####################################################################
## Class Initialisation
# (None)
